package db

import (
	"dc-news/common/utils"
	"dc-news/dao/model"
	"dc-news/entity"
	"encoding/json"
	"errors"
	"github.com/spf13/cast"
	"go.uber.org/zap"
	"time"
)

// GetChannelsByUserId 通过用户id获取已关注的频道
func GetChannelsByUserId(userId int) (channels []string, err error) {
	err = DB.
		Model(&entity.UserChannel{}).
		Select("channel").
		Where("user_id = ?", userId).
		Find(&channels).
		Error
	if err != nil {
		zap.S().Error("通过用户id获取已关注的频道操作数据库错误: ", err)
		return nil, err
	}
	return
}

// GetAllIdByChannel 通过channel获取全部新闻id
func GetAllIdByChannel(channel string) ([]int, error) {
	allId := make([]int, 0)
	tx := DB.Model(&entity.News{}).Select("id")
	if channel != "__all__" {
		tx = tx.Where("channel = ?", channel)
	}
	err := tx.Find(&allId).Error
	if err != nil {
		zap.S().Error("通过channel获取全部新闻id错误")
	}
	return allId, err
}

// GetNewsAbstractById 通过新闻id获取摘要
func GetNewsAbstractById(id int) (abstract *model.NewsAbstract, err error) {
	news := new(entity.News)
	err = DB.Model(&entity.News{}).Where("id = ?", id).Find(news).Error
	abstract = &model.NewsAbstract{
		ID:    news.ID,
		Title: news.Title,
		Type:  news.Type,
		Media: func() []string {
			medias := new([]string)
			_ = json.Unmarshal(news.Media, medias)
			return *medias
		}(),
		Channel:     news.Channel,
		PublishTime: news.PublishTime,
	}
	if err != nil {
		zap.S().Error("通过id获取新闻摘要操作数据库错误: ", err)
	}
	return abstract, err
}

// GetNewsById 通过id获取新闻
func GetNewsById(id int) (news *model.News, err error) {
	news = new(model.News)
	dbNews := &entity.News{}
	err = DB.Model(&entity.News{}).Where("id = ?", id).Find(dbNews).Error
	if err != nil {
		zap.S().Error("通过id获取新闻操作数据库错误: ", err)
		return nil, err
	}
	news.ID = dbNews.ID
	news.Title = dbNews.Title
	news.Content = dbNews.Content
	news.Channel = dbNews.Channel
	news.PublishTime = dbNews.PublishTime
	return
}

// GetNewsLikeByID 通过id获取新闻点赞数量
func GetNewsLikeByID(id int) (like int) {
	var count int64
	DB.Model(&entity.NewsLikes{}).Where("news_id = ?", id).Count(&count)
	return cast.ToInt(count)
}

// AddFavouriteNewsByUserIdAndNewsId 添加收藏
func AddFavouriteNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	err = DB.Create(&entity.Favorites{
		UserId: userId,
		NewsId: newsId,
	}).Error
	return
}

// RemoveFavouriteNewsByUserIdAndNewsId 移除收藏
func RemoveFavouriteNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	err = DB.
		Model(&entity.Favorites{}).
		Where("user_id = ? and news_id = ?", userId, newsId).
		Delete(&entity.Favorites{}).
		Error
	return
}

// LikesNewsByUserIdAndNewsId 通过用户id和新闻id点赞新闻
func LikesNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	var count int64
	DB.Model(&entity.NewsLikes{}).Where("news_id = ? and user_id = ?", newsId, userId).Count(&count)
	if count != 0 {
		return errors.New("has been liked")
	}
	err = DB.Create(&entity.NewsLikes{
		NewsId:   newsId,
		UserId:   userId,
		LikeTime: time.Now().Unix(),
	}).Error
	if err != nil {
		zap.S().Error("通过用户id和新闻id点赞新闻操作数据库错误: ", err)
	}
	return
}

// CancelLikesNewsByUserIdAndNewsId 通过用户id和新闻id取消点赞新闻
func CancelLikesNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	var count int64
	DB.Model(&entity.NewsLikes{}).Where("news_id = ? and user_id = ?", newsId, userId).Count(&count)
	if count == 0 {
		return errors.New("has not been liked")
	}
	err = DB.
		Model(&entity.NewsLikes{}).
		Where("user_id = ? and news_id = ?", userId, newsId).
		Delete(&entity.NewsLikes{}).
		Error
	if err != nil {
		zap.S().Error("通过用户id和新闻id取消点赞新闻操作数据库错误: ", err)
	}
	return
}

// GetUserFavouriteNewsById 获取用户收藏新闻列表
func GetUserFavouriteNewsById(id int, p *utils.Pagination) (*[]model.NewsList, error) {
	news := make([]model.NewsList, 0)
	err := DB.Model(&entity.News{}).
		Joins("join favourites on favourites.news_id=news.id").
		Where("favourites.user_id = ?", id).
		Scopes(p.GormPaginate()).
		Find(&news).
		Error
	if err != nil {
		zap.S().Error("获取用户收藏新闻列表操作数据库错误: ", err)
		return nil, err
	}
	var count int64
	DB.Model(&entity.Favorites{}).Where("user_id = ?", id).Count(&count)
	p.Total = cast.ToInt(count)
	return &news, nil
}

// GetUserLikesNewsById 获取用户点赞新闻列表
func GetUserLikesNewsById(id int, p *utils.Pagination) (*[]model.NewsList, error) {
	news := make([]model.NewsList, 0)
	err := DB.Model(&entity.News{}).
		Joins("join news_likes on news_likes.news_id=news.id").
		Where("news_likes.user_id = ?", id).
		Scopes(p.GormPaginate()).
		Find(&news).
		Error
	if err != nil {
		zap.S().Error("获取用户点赞新闻列表操作数据库错误: ", err)
		return nil, err
	}
	var count int64
	DB.Model(&entity.NewsLikes{}).Where("user_id = ?", id).Count(&count)
	p.Total = cast.ToInt(count)
	return &news, nil
}

// GetAllNewsLikeByUserId 获取用户全部点赞新闻id
func GetAllNewsLikeByUserId(id int) (*[]int, error) {
	ids := make([]int, 0)
	err := DB.
		Model(&entity.NewsLikes{}).
		Select("news_id").
		Where("user_id = ?", id).
		Find(&ids).
		Error
	if err != nil {
		zap.S().Error("获取用户全部点赞新闻id操作数据库错误: ", err)
		return &ids, err
	}
	return &ids, err
}

// GetAllNewsFavouriteByUserId 获取用户全部收藏新闻id
func GetAllNewsFavouriteByUserId(id int) (*[]int, error) {
	ids := make([]int, 0)
	err := DB.
		Model(&entity.Favorites{}).
		Select("news_id").
		Where("user_id = ?", id).
		Find(&ids).
		Error
	if err != nil {
		zap.S().Error("获取用户全部收藏新闻id操作数据库错误: ", err)
		return &ids, err
	}
	return &ids, err
}

// AddChannelByUserId 通过用户id添加关注频道
func AddChannelByUserId(id int, channel string) (err error) {
	err = DB.Create(&entity.UserChannel{
		UserId:  id,
		Channel: channel,
	}).Error
	if err != nil {
		zap.S().Error("通过用户id添加关注频道操作数据库错误: ", err)
	}
	return err
}

// RemoveChannelByUserId 通过用户id移除关注频道
func RemoveChannelByUserId(id int, channel string) (err error) {
	err = DB.
		Model(&entity.UserChannel{}).
		Where("user_id = ? and channel = ?", id, channel).
		Delete(&entity.UserChannel{}).
		Error
	if err != nil {
		zap.S().Error("通过用户id移除关注频道操作数据库错误: ", err)
	}
	return
}

// GetNewsLikeById 获取新闻点赞数量
func GetNewsLikeById(userId int, after int64) int {
	var count int64
	DB.Model(&entity.NewsLikes{}).Where("user_id = ? and like_time > ?", userId, after).Count(&count)
	return cast.ToInt(count)
}
